export type TDirModuleItem =
  | {
      isDir: true;
      name: string;
      hyphenStyleName: string;
      files: Array<TDirModuleItem>;
      dirPathArr: Array<string>;
    }
  | {
      /**
       * 是否为目录
       */
      isDir: false;
      /**
       * 目录或文件名称
       */
      name: string;
      /**
       * 连字符风格名称
       */
      hyphenStyleName: string;
      /**
       * 文件扩展名
       */
      fileExtension: string;
      /**
       * 父级目录路径数组
       */
      dirPathArr: Array<string>;
      /**
       * 文件模块
       */
      module: any;
      /**
       * 当前文件路径
       */
      fillPath: string;
    };

export const isDir = (item: TDirModuleItem): item is Exclude<TDirModuleItem, { isDir: false }> =>
  item.isDir;

/**
 * 将字符串转换为连字符命名风格
 * @param str
 * @returns
 */
const toHyphenStyleStr = (str: string) => {
  /**
   * 匹配字符串开头的 空格、-、_
   */
  const reg1 = /^[ \-_]+/g;
  /**
   * 匹配字符串中的 空格、-、_
   */
  const reg2 = /[ \-_]+/g;
  /**
   * 匹配非开头且前面不是 空格、-、_、大写字母的大写字母
   */
  const reg3 = /(?<!^)(?<![ -_A-Z])([A-Z])/g;

  return str.replace(reg1, '').replace(reg2, '-').replace(reg3, '-$1').toLocaleLowerCase();
};

const getDirMap = (
  moduleItem: TDirModuleItem,
  dirPathArr: Array<string>,
  pathIndex: number,
  filesArr: Exclude<TDirModuleItem, { isDir: false }>['files'] = []
) => {
  const dirName = dirPathArr[pathIndex];
  if (dirName === undefined) return filesArr.push(moduleItem);
  let dirItem = filesArr.find(
    (item) => item.name === dirName && (item as Exclude<TDirModuleItem, { isDir: false }>).isDir
  ) as Exclude<TDirModuleItem, { isDir: false }> | undefined;
  if (dirItem === undefined) {
    dirItem = {
      isDir: true,
      name: dirName,
      hyphenStyleName: toHyphenStyleStr(dirName),
      files: [],
      dirPathArr: dirPathArr.slice(0, pathIndex)
    };
    filesArr.push(dirItem);
  }
  getDirMap(moduleItem, dirPathArr, pathIndex + 1, dirItem.files);
  return dirItem;
};

const getDirModuleMap = (modules: Record<string, () => Promise<any>> | any) => {
  const moduleArr: Array<Exclude<TDirModuleItem, { isDir: true }>> = [];
  for (const path in modules) {
    const dirArr = path.split('/').slice(3);
    const moduleFile = dirArr.pop()!;
    let sliceIndex = moduleFile!.search(/\.[^.]+$/);
    if (sliceIndex === -1) sliceIndex = moduleFile.length + 1;
    const moduleItem: TDirModuleItem = {
      isDir: false,
      name: moduleFile.slice(0, sliceIndex),
      hyphenStyleName: toHyphenStyleStr(moduleFile.slice(0, sliceIndex)),
      fileExtension: moduleFile.slice(sliceIndex),
      dirPathArr: dirArr,
      module: modules[path],
      fillPath: path
    };
    moduleArr.push(moduleItem);
  }
  return moduleArr.reduce<Array<TDirModuleItem>>((result, item) => {
    getDirMap(item, [...item.dirPathArr], 0, result);
    return result;
  }, []);
};

export default getDirModuleMap;
